package com.dqx.opengl_es_demo.face;

import android.content.Context;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;

import com.dqx.opengl_es_demo.R;
import com.dqx.utils.GLUtils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class GLFrame {
    /**
     * 顶点坐标数组
     */
    private final float[] vertexData = {
            1f, -1f, 0f,
            -1f, -1f, 0f,
            1f, 1f, 0f,
            -1f, 1f, 0f
    };
    /**
     * 纹理坐标数组
     */
    private final float[] textureVertexData = {
            1f, 0f,
            0f, 0f,
            1f, 1f,
            0f, 1f
    };
    //顶点缓冲区
    private FloatBuffer vertexBuffer;
    //纹理缓冲区
    private FloatBuffer textureVertexBuffer;
    //程序id
    private int programId;
    //顶点“位置”属性句柄
    private int aPositionHandle;
    //“外部纹理”属性句柄
    private int uTextureSamplerHandle;
    //“内部纹理”属性句柄
    private int iTextureSamplerHandle;
    //顶点“纹理坐标”属性句柄
    private int aTextureCoordHandle;
    //“矩阵”属性句柄
    private int uSTMMatrixHandle;
    //“饱和度”属性句柄
    private int sHandle;
    //“色调”属性句柄
    private int hHandle;
    //“亮度”属性句柄
    private int lHandle;
    //存储缓冲区对象id的数组
    private int[] vertexBuffers;

    //饱和度
    private float s = 1.0f;
    //色调
    private float h = 0.0f;
    //亮度
    private float l = 1.0f;

    private Rect rect = new Rect();

    //装载纹理缓冲区对象id的数组
    private int[] textures;

    private float[] mSTMatrix = new float[16];

    //纹理处理控件
    private SurfaceTexture surfaceTexture;

    private Context context;

    public GLFrame(Context context) {
        this.context = context;
        //初始化顶点缓冲区对象
        vertexBuffer = convertToFloatBuffer(vertexData);
        //初始化纹理缓冲区对象
        textureVertexBuffer = convertToFloatBuffer(textureVertexData);
    }

    /**
     * 设置渲染大小
     * （解决摄像头预览和GLSurfaceView的长宽比不一致导致的物体被拉伸变形的问题）
     *
     * @param width
     * @param height
     */
    private void setSize(int width, int height) {

        int left, top, viewWidth, viewHeight;
        //实际预览的宽高比
        float sh = width * 1.0f / height;
        //指定预览的高宽比
        float vh = CameraUtils.PREVIEW_HEIGHT * 1.0f / CameraUtils.PREVIEW_WIDTH;
        if (sh < vh) {
            left = 0;
            viewWidth = width;
            viewHeight = (int) (CameraUtils.PREVIEW_WIDTH * 1.0f / CameraUtils.PREVIEW_HEIGHT * viewWidth);
            top = (height - viewHeight) / 2;
        } else {
            top = 0;
            viewHeight = height;
            viewWidth = (int) (CameraUtils.PREVIEW_HEIGHT * 1.0f / CameraUtils.PREVIEW_WIDTH * viewHeight);
            left = (width - viewWidth) / 2;
        }
        rect.left = left;
        rect.top = top;
        rect.right = viewWidth;
        rect.bottom = viewHeight;
    }

    public void init(int width, int height) {
        setSize(width, height);
        //创建着色器程序
        programId = GLUtils.buildProgram(context, R.raw.camera_vertex, R.raw.camera_frag);
        //获取着色器程序属性
        aPositionHandle = GLES20.glGetAttribLocation(programId, "aPosition");
        uSTMMatrixHandle = GLES20.glGetUniformLocation(programId, "uSTMatrix");
        uTextureSamplerHandle = GLES20.glGetUniformLocation(programId, "sTexture");
        iTextureSamplerHandle = GLES20.glGetUniformLocation(programId, "iTexture");
        aTextureCoordHandle = GLES20.glGetAttribLocation(programId, "aTexCoord");
        sHandle = GLES20.glGetUniformLocation(programId, "S");
        hHandle = GLES20.glGetUniformLocation(programId, "H");
        lHandle = GLES20.glGetUniformLocation(programId, "L");

        vertexBuffers = new int[2];
        //生成2个坐标缓冲区对象
        GLES20.glGenBuffers(2, vertexBuffers, 0);
        //绑定id为vertexBuffers[0]的缓冲区对象
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBuffers[0]);
        //创建并初始化缓冲区对象的数据存储（顶点坐标数据）
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexData.length * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);
        //绑定id为vertexBuffers[1]的缓冲区对象
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBuffers[1]);
        //创建并初始化缓冲区对象的数据存储（纹理坐标数据）
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, textureVertexData.length * 4, textureVertexBuffer, GLES20.GL_STATIC_DRAW);

        textures = new int[2];
        //生成2个纹理对象
        GLES20.glGenTextures(2, textures, 0);
        //绑定id为textures[0]的纹理对象
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
        //纹理过滤
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
        //指定一个二维纹理图像
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, CameraUtils.PREVIEW_WIDTH, CameraUtils.PREVIEW_HEIGHT,
                0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
        //绑定id为textures[1]的纹理对象
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[1]);
    }

    public void drawFram() {
        //动态设置窗口的绘制区域
        GLES20.glViewport(rect.left, rect.top, rect.right, rect.bottom);
        //使用程序
        GLES20.glUseProgram(programId);
        //绑定id为vertexBuffers[0]的缓冲区对象
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBuffers[0]);
        //启用顶点“顶点坐标”属性数组
        GLES20.glEnableVertexAttribArray(aPositionHandle);
        //定义顶点属性数组
        GLES20.glVertexAttribPointer(aPositionHandle, 3, GLES20.GL_FLOAT, false,
                0, 0);
        //绑定id为vertexBuffers[1]的缓冲区对象
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vertexBuffers[1]);
        //启用顶点“纹理坐标”属性数组
        GLES20.glEnableVertexAttribArray(aTextureCoordHandle);
        //定义顶点属性数组
        GLES20.glVertexAttribPointer(aTextureCoordHandle, 2, GLES20.GL_FLOAT, false, 0, 0);

        //绑定纹理，将纹理值传递给着色器
        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
        GLES20.glUniform1i(iTextureSamplerHandle, 1);

        //绑定纹理，将纹理值传递给着色器
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, textures[1]);
        GLES20.glUniform1i(uTextureSamplerHandle, 0);

        //指定uSTMMatrixHandle变量的值
        GLES20.glUniformMatrix4fv(uSTMMatrixHandle, 1, false, mSTMatrix, 0);

        if (surfaceTexture != null) {
            surfaceTexture.updateTexImage();
            surfaceTexture.getTransformMatrix(mSTMatrix);
        }
        GLES20.glUniform1f(sHandle, s);
        GLES20.glUniform1f(hHandle, h);
        GLES20.glUniform1f(lHandle, l);
        //绘制
        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
    }

    public void setS(float s) {
        this.s = s;
    }

    public void setH(float h) {
        this.h = h;
    }

    public void setL(float l) {
        this.l = l;
    }

    public SurfaceTexture getSurfaceTexture() {
        surfaceTexture = new SurfaceTexture(textures[1]);
        return surfaceTexture;
    }

    public void release() {
        if (surfaceTexture != null)
            surfaceTexture.release();

        //删除OpenGL-ES程序
        GLES20.glDeleteProgram(programId);
        //删除缓冲区数据
        GLES20.glDeleteBuffers(2, vertexBuffers, 0);
        //删除纹理数据
        GLES20.glDeleteTextures(2, textures, 0);
    }

    /**
     * 转换为缓冲区对象
     *
     * @param buffer
     * @return
     */
    private FloatBuffer convertToFloatBuffer(float[] buffer) {
        FloatBuffer fb = (FloatBuffer) ByteBuffer.allocateDirect(buffer.length * 4)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer()
                .put(buffer)
                .position(0);
        return fb;
    }
}
